<#assign object = doc.object>
package ${object.package}.service;

import javax.servlet.http.HttpServletRequest;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONUtils;
<#if object.attributes.set[0]??>
import net.sf.json.JSONArray;
</#if>
import java.io.*;
import java.sql.ResultSet;
<#if object.attributes.xml[0]??>
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBException;
import ${object.package}.model.xml.*;
</#if>
import java.text.ParseException;
import java.util.Date;
<#list doc["//enum[@scope='global']"] as enum>
import ${object.package}.model.enums.${enum.@class};
</#list>

import ${object.package}.model.*;
import ${object.package}.model.fields.*;
import redora.rdo.exceptions.*;
import redora.rdo.util.Constants;

public class ${object.name}Util {
	public static final String NULL = "null";
	
	/**
	* Copies te resultset into a a ${object.name}. 
	* The resultset is default parsed by index for maximum performance.
	* @param rs	(Mandatory) ResultSet containing all fields listed in ${object.name}Fields
	* @param offset	(Mandatory) Almost always 0. When performing a query on multiple tables give the offset of the fields in the select.
	* @see ${object.name}Fields
	**/
 	public static ${object.name} copy(ResultSet rs, int offset) throws CopyException {
  		${object.name} retval = new ${object.name}();
		retval.isNew = false;
		try {
	<#assign position = 1>
			retval.id = Long.valueOf(rs.getLong(${position} + offset));
<#list object.attributes?children as att>
	<#if att?node_name != "set" && att?node_type == "element">
		<#if !(att.@lazy[0]?? && att.@lazy == "true") && att?node_name != "xml">
			<#assign position = position + 1>
   			<#if att?node_name == "boolean">
	    	if (!rs.wasNull())
	      		retval.${att.@name} = Boolean.valueOf(rs.getBoolean(${position} + offset));
	    	else
	      		retval.${att.@name} = null;
   			<#elseif att?node_name == "date" || att?node_name == "datetime">
	    	java.sql.Date ${att.@name} = rs.getDate(${position} + offset);
	    	if (${att.@name} != null)
	      		retval.${att.@name} = new Date(${att.@name}.getTime());
	    	else
	      		retval.${att.@name} = null;
    		<#elseif att?node_name=="string">
   				<#if att.@maxlength[0]?number &gt; 65000>
	      	java.io.InputStream ${att.@name}Stream = rs.getBinaryStream(${position} + offset);
	      	if (${att.@name}Stream != null)
	      		retval.${att.@name} = org.apache.commons.io.IOUtils.toString(${att.@name}Stream);			
   				<#else>
	  		retval.${att.@name} = rs.getString(${position} + offset);
    			</#if>
			<#elseif att?node_name=="long">
	    	long ${att.@name} = rs.getLong(${position} + offset);
	    	if (!rs.wasNull())
	      		retval.${att.@name} = Long.valueOf(${att.@name});
	    	else
	      		retval.${att.@name} = null;
			<#elseif att?node_name=="object">
	    	long ${att.@class?uncap_first}Id = rs.getLong(${position} + offset);
	    	if (!rs.wasNull())
	      		retval.${att.@class?uncap_first}Id = Long.valueOf(${att.@class?uncap_first}Id);
	    	else
	      		retval.${att.@class?uncap_first}Id = null;
			<#elseif att?node_name=="integer">
	    	int ${att.@name} = rs.getInt(${position} + offset);
	    	if (!rs.wasNull())
	      		retval.${att.@name} = Integer.valueOf(${att.@name});
	    	else
	      		retval.${att.@name} = null;
			<#elseif att?node_name=="enum">
      		retval.${att.@class?uncap_first} = <#if !att.@scope[0]?? || att.@scope[0] == "local">${object.name}.</#if>${att.@class}.valueOfNullSafe(rs.getString(${position} + offset));
			<#elseif att?node_name=="xml">
	    	${object.package}.model.xml.<#if att.@class[0]??>${att.@class}<#else>${att.@name?cap_first}</#if> ${att.@name}_doc = null;
	    	java.io.InputStream in = null;
			in = rs.getBinaryStream(${position} + offset);
	    	try {
				javax.xml.bind.JAXBContext ${att.@name}_ctx = javax.xml.bind.JAXBContext
						.newInstance(new Class[] { ${object.package}.model.xml.<#if att.@class[0]??>${att.@class}<#else>${att.@name?cap_first}</#if>.class });
				javax.xml.bind.Unmarshaller ${att.@name}_um = ${att.@name}_ctx.createUnmarshaller();
				if (in != null)
					${att.@name}_doc = (${object.package}.model.xml.<#if att.@class[0]??>${att.@class}<#else>${att.@name?cap_first}</#if>) ${att.@name}_um.unmarshal(in);
				else
					${att.@name}_doc = null;
			} catch (JAXBException e) {
				throw new CopyException("Failed to bind ${att.@name}!", e);
			}
			retval.set${att.@name?cap_first}(${att.@name}_doc);
			</#if>
		</#if>
	</#if>
</#list>
			<#assign position = position + 1>
			retval.creationDate = new Date(rs.getTimestamp(${position} + offset).getTime());
			<#assign position = position + 1>
			java.sql.Timestamp updateDate = rs.getTimestamp(${position} + offset);
			if (updateDate != null)
				retval.updateDate = new Date(updateDate.getTime());
			retval.clean();
		} catch (Exception e) {
			throw new CopyException("Failed to copy from table to object ${object.name}",e);
		}
		return retval;
  	}

	/**
	* Copies te resultset into a JSON stream. 
	* The resultset is default parsed by index for maximum performance.
	* @param rs	(Mandatory) ResultSet containing all fields listed in ${object.name}Fields
	* @param offset	(Mandatory) Almost always 0. When performing a query on multiple tables give the offset of the fields in the select.
	* @param out (Mandatory) The output stream typically routed to your servlets' writer stream.
	**/
 	public static void jsonStream(ResultSet rs, int offset, PrintWriter out) throws CopyException {
		try {
			out.print('{');
			<#assign position = 1>
			out.print("\"id\":");
			out.print(rs.getLong(${position} + offset));
			out.print(',');
	    	<#list object.attributes?children as att>
	    		<#if att?node_name != "set" && att?node_type == "element">
	    			<#if !(att.@lazy[0]?? && att.@lazy == "true") && att?node_name != "xml">
				<#assign position = position + 1>
		    		<#if att?node_name == "date" || att?node_name == "datetime">
	    	out.print("\"${att.@name}\":");
	    	java.sql.Date _${att.@name} = rs.getDate(${position} + offset);
	    	if (_${att.@name} != null) {
	    		out.print('\"');
	      		out.print(Constants.${att?node_name?upper_case}.format(new Date(_${att.@name}.getTime())));
	      		out.print('\"');
	    	} else
	      		out.print(NULL);
	    			<#elseif att?node_name=="long" || att?node_name=="integer">
	    	out.print("\"${att.@name}\":");
	    	String _${att.@name} = rs.getString(${position} + offset);
	    	if (_${att.@name} != null)
	      		out.print(_${att.@name});
	    	else
	      		out.print("null");
	    			<#elseif att?node_name=="xml">
	    	out.print("\"${att.@name}\":");
	    	if(rs.getObject(${position} + offset) != null){
	    		out.print('\"');
	    		org.apache.commons.io.IOUtils.copy(rs.getBinaryStream(${position} + offset), out);
	    		out.print('\"');
	    	} else
	    		out.print(NULL);
	    			<#elseif att?node_name=="object">
	    	out.print("\"${att.@class}Id\":");
	    	if(rs.getObject(${position} + offset) != null){
	    		out.print("\"");
	    		org.apache.commons.io.IOUtils.copy(rs.getBinaryStream(${position} + offset), out);
	    		out.print("\"");
	    	} else {
	    		out.print(NULL);
	    	}
	    			<#elseif att?node_name=="boolean">
	    	out.print("\"${att.@name}\":");
	    	if (rs.getObject(${position} + offset) != null) 
	    		out.print(Boolean.valueOf(rs.getBoolean(${position} + offset)));
	    	else 
	    		out.print(NULL);
	    			<#else>
	    	out.print("\"${att.@name[0]!att.@class?uncap_first}\":");
	    	String _${att.@name[0]!att.@class?uncap_first} = rs.getString(${position} + offset);
	    	if (_${att.@name[0]!att.@class?uncap_first} != null) {
	      		out.print(JSONUtils.valueToString(_${att.@name[0]!att.@class?uncap_first}));
	    	} else
	      		out.print(NULL);
		      		</#if>
		    out.print(',');
		      	</#if>
		      	</#if>
		    </#list>
			<#assign position = position + 1>
			out.print("\"creationDate\":\"");
			out.print(rs.getTimestamp(${position} + offset).toString());
			out.print('\"');
			out.print(',');
			<#assign position = position + 1>
			java.sql.Timestamp updateDate = rs.getTimestamp(${position} + offset);
			out.print("\"updateDate\":");
			if (updateDate != null) {
				out.print('\"');
				out.print(updateDate.toString());
				out.print('\"');
			} else
				out.print(NULL);
			out.print('}');
		} catch (Exception e) {
			throw new CopyException("Failed to copy from ResultSet into JSON for ${object.name}",e);
		}
  	}

	
	/**
    * Copies from JSON to ${object.name}.
    * Be sure you have initialized ${object.name} before running the copy. When you copy an existing ${object.name},
    * retrieve the last version from the database. In this way it will be known which attributes have been changed.
    **/
	public static void copy(JSONObject obj, ${object.name} pojo) throws CopyException, LazyException {
		if ((obj.has(${object.name}Fields.id.name()) && !(obj.getLong(${object.name}Fields.id.name()) == pojo.getId()) || (pojo.getId() != null && !obj.has(${object.name}Fields.id.name()))))
			throw new CopyException("You are trying to update ${object.name} with id " + pojo.id + " with the values of another ${object.name} (" + obj.getLong(${object.name}Fields.id.name()) + ").",null);
		<#list object.attributes?children as att>
			<#if att?node_name == "long">
		if (obj.has(${object.name}Fields.${att.@name}.name()) && obj.getString(${object.name}Fields.${att.@name}.name()) != NULL )
			pojo.set${att.@name?cap_first}(obj.getLong(${object.name}Fields.${att.@name}.name()));		
		else 
			pojo.set${att.@name?cap_first}(null);
			<#elseif att?node_name == "integer">
		if (obj.has(${object.name}Fields.${att.@name}.name()) && obj.getString(${object.name}Fields.${att.@name}.name()) != NULL)
			pojo.set${att.@name?cap_first}(obj.getInt(${object.name}Fields.${att.@name}.name()));
		else
			pojo.set${att.@name?cap_first}(null);
			<#elseif att?node_name == "string">
		if (obj.has(${object.name}Fields.${att.@name}.name()) && obj.getString(${object.name}Fields.${att.@name}.name()) != NULL) {
			<#if att.@lazy[0]?? && att.@lazy=="true">
			try {
				pojo.set${att.@name?cap_first}(obj.getString(${object.name}Fields.${att.@name}.name()));
			} catch(LazyException e) {
				throw new CopyException("Failed to retrieved the lazy ${att.@name}", e);
			}
			<#else>
			pojo.set${att.@name?cap_first}(obj.getString(${object.name}Fields.${att.@name}.name()));
			</#if>
		} else 
			pojo.set${att.@name?cap_first}(null);
			<#elseif att?node_name == "enum">
		if (obj.has(${object.name}Fields.${att.@class?uncap_first}.name()) && obj.getString(${object.name}Fields.${att.@class?uncap_first}.name()) != "null")
			pojo.set${att.@class}(<#if !att.@scope[0]?? || att.@scope[0] == "local">${object.name}.</#if>${att.@class}.valueOfNullSafe(obj.getString(${object.name}Fields.${att.@class?uncap_first}.name())));
		else 
			pojo.set${att.@class}(null);
			<#elseif att?node_name == "date" || att?node_name == "datetime">
		if (obj.has(${object.name}Fields.${att.@name}.name()) && obj.getString(${object.name}Fields.${att.@name}.name()) != NULL) {
			try {
				pojo.set${att.@name?cap_first}(Constants.${att?node_name?upper_case}.parse(obj.getString(${object.name}Fields.${att.@name}.name())));
			} catch(ParseException e) {
				throw new CopyException("Failed to copy this date: " + obj.getString(${object.name}Fields.${att.@name}.name()), e);
			}
		} else 
			pojo.set${att.@name?cap_first}(null);
			<#elseif att?node_name == "xml">
		if (obj.has(${object.name}Fields.${att.@name}.name()) && obj.getString(${object.name}Fields.${att.@name}.name()) != NULL) {
			try {
				JAXBContext ${att.@name}_ctx = javax.xml.bind.JAXBContext.newInstance(new Class[] { <#if att.@class[0]??>${att.@class}<#else>${att.@name?cap_first}</#if>.class });
				Unmarshaller ${att.@name}_um = ${att.@name}_ctx.createUnmarshaller();
				InputStream stream = new ByteArrayInputStream(obj.getString(${object.name}Fields.${att.@name}.name())
						.getBytes());
				pojo.set${att.@name?cap_first}((<#if att.@class[0]??>${att.@class}<#else>${att.@name?cap_first}</#if>) ${att.@name}_um.unmarshal(stream));
			} catch (JAXBException e) {
				throw new CopyException("Failed to bind ${att.@name}!", e);
			}
		} else 
			pojo.set${att.@name?cap_first}(null);
			<#elseif att?node_name == "set">
		if (obj.has("<#if att.@plural[0]??>${att.@plural}<#else>${att.@class}s</#if>") && obj.getString("<#if att.@plural[0]??>${att.@plural}<#else>${att.@class}s</#if>") != NULL) {
			JSONArray array = JSONArray.fromObject(obj.get("<#if att.@plural[0]??>${att.@plural}<#else>${att.@class}s</#if>"));
			for (int i = 0; i < array.size(); i++) {
				${att.@class} ${att.@class?uncap_first} = new ${att.@class}();
				JSONObject ${att.@class?uncap_first}Obj = array.getJSONObject(i);
				${att.@class}Util.copy(${att.@class?uncap_first}Obj, ${att.@class?uncap_first});
				try {
					pojo.get<#if att.@plural[0]??>${att.@plural?cap_first}<#else>${att.@class}s</#if>().add(${att.@class?uncap_first});
				} catch(PersistenceException e) {
					throw new CopyException("Copy failed with pojo.get<#if att.@plural[0]??>${att.@plural?cap_first}<#else>${att.@class}s</#if>()", e);
				}
			}
		}
			<#elseif att?node_name == "boolean">
		if (obj.has(${object.name}Fields.${att.@name}.name()) && obj.getString(${object.name}Fields.${att.@name}.name()) != NULL)
			pojo.set${att.@name?cap_first}(obj.getBoolean(${object.name}Fields.${att.@name}.name()));
		else
			pojo.set${att.@name?cap_first}(null);
			</#if>
		</#list>
		if (obj.has(${object.name}Fields.creationDate.name()) && obj.getString(${object.name}Fields.creationDate.name()) != NULL) {
			try {
				pojo.creationDate = new Date((Constants.DATETIME.parse(obj.getString(${object.name}Fields.creationDate.name())).getTime()/1000)*1000);
			} catch(ParseException e) {
				throw new CopyException("Failed to copy this date: " + obj.getString(${object.name}Fields.creationDate.name()), e);
			}
		}
		if (obj.has(${object.name}Fields.updateDate.name()) && obj.getString(${object.name}Fields.updateDate.name()) != NULL) {
			try {
				pojo.updateDate = new Date((Constants.DATETIME.parse(obj.getString(${object.name}Fields.updateDate.name())).getTime()/1000)*1000);
			} catch(ParseException e) {
				throw new CopyException("Failed to copy this date: " + obj.getString(${object.name}Fields.updateDate.name()), e);
			}
		}
	}
	
	/**
	    * Copies from ${object.name} to PrinterWriter.
	    **/
		public static void copy(${object.name} pojo, PrintWriter out) throws CopyException, LazyException {
			try {
			out.print('{');
			out.print("\"id\":");
			out.print(pojo.getId());
			out.print(',');
	    	<#list object.attributes?children as att>
	    		<#if att?node_name != "set" && att?node_type == "element">
	    			<#if !(att.@lazy[0]?? && att.@lazy == "true") && att?node_name != "xml">
		    		<#if att?node_name == "date" || att?node_name == "datetime">
	    	out.print("\"${att.@name}\":");
	    	Date _${att.@name} = pojo.get${att.@name?cap_first}();
	    	if (_${att.@name} != null) {
	    		out.print('\"');
	      		out.print(Constants.${att?node_name?upper_case}.format(new Date(_${att.@name}.getTime())));
	      		out.print('\"');
	    	} else
	      		out.print(NULL);
	    			<#elseif att?node_name=="long">
	    	out.print("\"${att.@name}\":");
	    	Long _${att.@name} = pojo.get${att.@name?cap_first}();
	    	if (_${att.@name} != null)
	      		out.print(_${att.@name});
	    	else
	      		out.print(NULL);
	      			<#elseif att?node_name=="integer">
	      	out.print("\"${att.@name}\":");
	    	int _${att.@name} = pojo.get${att.@name?cap_first}();
	    	if (_${att.@name} != 0)
	      		out.print(_${att.@name});
	    	else
	      		out.print(NULL);
	    			<#elseif att?node_name=="xml">
	    	out.print("\"${att.@name}\":");
	    	out.print(NULL);
	    			<#elseif att?node_name=="object">
	    	out.print("\"${att.@class}Id\":");
	    	if(pojo.get${att.@class}() != null){
	    		out.print(pojo.get${att.@class}Id());
	    	} else {
	    		out.print(NULL);
	    	}
	    			<#elseif att?node_name=="boolean">
	    	out.print("\"${att.@name}\":");
	    	if (pojo.get${att.@name?cap_first}() != null) 
	    		out.print(Boolean.valueOf(pojo.get${att.@name?cap_first}()));
	    	else 
	    		out.print(NULL);
	    			<#elseif att?node_name=="enum">
	    	out.print("\"${att.@class?uncap_first}\":");
	    	if (pojo.get${att.@class}() != null) 
	    		out.print(pojo.get${att.@class}());
	    	else 
	    		out.print(NULL);
	    			<#else>
	    	out.print("\"${att.@name[0]!att.@class?uncap_first}\":");
	    	String _${att.@name[0]!att.@class?uncap_first} = pojo.get${att.@name?cap_first}();
	    	if (_${att.@name[0]!att.@class?uncap_first} != null) {
	      		out.print(JSONUtils.valueToString(_${att.@name[0]!att.@class?uncap_first}));
	    	} else
	      		out.print(NULL);
		      		</#if>
		    out.print(',');
		      	</#if>
		      	</#if>
		    </#list>
			out.print("\"creationDate\":\"");
			out.print(pojo.getCreationDate().toString());
			out.print('\"');
			out.print(',');
			Date updateDate = pojo.getUpdateDate();
			out.print("\"updateDate\":");
			if (updateDate != null) {
				out.print('\"');
				out.print(updateDate.toString());
				out.print('\"');
			} else
				out.print(NULL);
			out.print('}');
		} catch (Exception e) {
			throw new CopyException("Failed to copy from ResultSet into JSON for ${object.name}",e);
		}
		}
	
	public static JSONObject getJSONValue(HttpServletRequest request){
		JSONObject json = new JSONObject();
		if (request.getParameter(${object.name}Fields.id.name()) != null)
			json.put(${object.name}Fields.id.name(), request
					.getParameter(${object.name}Fields.id.name()));
		<#list object.attributes?children as att>
			<#if att?node_name != "set" && att?node_name != "object" && att?node_type == "element">
			<#if att?node_name == "long">
		if (request.getParameter(${object.name}Fields.${att.@name}.name()) != null && !request.getParameter(${object.name}Fields.${att.@name}.name()).equals(NULL))
			json.put(${object.name}Fields.${att.@name}.name(), Long.valueOf(request
					.getParameter(${object.name}Fields.${att.@name}.name())));
			<#elseif att?node_name == "integer">
		if (request.getParameter(${object.name}Fields.${att.@name}.name()) != null && !request.getParameter(${object.name}Fields.${att.@name}.name()).equals(NULL))
			json.put(${object.name}Fields.${att.@name}.name(), Integer.parseInt(request
					.getParameter(${object.name}Fields.${att.@name}.name())));
			<#else>
		if (request.getParameter(${object.name}Fields.${att.@name[0]!att.@class?uncap_first}.name()) != null && !request.getParameter(${object.name}Fields.${att.@name[0]!att.@class?uncap_first}.name()).equalsIgnoreCase("null"))
			json.put(${object.name}Fields.${att.@name[0]!att.@class?uncap_first}.name(), request
					.getParameter(${object.name}Fields.${att.@name[0]!att.@class?uncap_first}.name()));
			</#if>
			</#if>
		</#list>
		return json;
	}
}
